package com.lvkerry.orderfood.provider.store;

import com.lvkerry.orderfood.provider.WxDevelopIdStore;
import org.jetbrains.annotations.NotNull;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * @author Kerry
 */

public class InMemoryWxDevelopIdStore implements WxDevelopIdStore {

    private final DelayQueue<TokenExpiry> expiryQueue = new DelayQueue<>();
    private final ConcurrentHashMap<String, TokenExpiry> expiryMap = new ConcurrentHashMap<>();

    @SuppressWarnings("AlibabaAvoidManuallyCreateThread")
    public InMemoryWxDevelopIdStore() {
        Runnable daemonTask = this::daemonCheck;
        Thread daemonThread = new Thread(daemonTask);
        daemonThread.setDaemon(true);
        daemonThread.setName("InMemoryWxDevelopIdStore-Daemon-Thread");
        daemonThread.start();
    }

    private void daemonCheck() {
        for (; ; ) {
            try {
                expiryQueue.take();
                expiryMap.remove(WEI_XIN_DEVELOP_ID);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //TODO is break ? break;
                break;
            }
        }
    }

    @Override
    public void setCache(String token, long expire) {
        TokenExpiry o = new TokenExpiry(WEI_XIN_DEVELOP_ID, token, expire);
        expiryQueue.remove(o);
        expiryQueue.put(o);
        expiryMap.put(WEI_XIN_DEVELOP_ID, o);
    }

    @Override
    public String getCache() {
        TokenExpiry expiry = expiryMap.get(WEI_XIN_DEVELOP_ID);
        if (expiry != null) {
            return expiry.getVlaue();
        }
        return null;
    }

    @Override
    public long getExpiry() {
        TokenExpiry expiry = expiryMap.get(WEI_XIN_DEVELOP_ID);
        if (expiry != null) {
            return expiry.getDelay(TimeUnit.MILLISECONDS);
        }
        return -1L;
    }


    private static class TokenExpiry implements Delayed {

        private final long expiry;

        private final String key;

        private final String vlaue;

        public TokenExpiry(String key, String vlaue, long delaySecond) {
            this.key = key;
            this.vlaue = vlaue;
            this.expiry = System.currentTimeMillis() + (1000 * delaySecond);
        }

        @Override
        public int compareTo(@NotNull Delayed other) {
            if (this == other) {
                return 0;
            }
            long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
            return (diff == 0 ? 0 : ((diff < 0) ? -1 : 1));
        }

        @Override
        public long getDelay(@NotNull TimeUnit unit) {
            return expiry - System.currentTimeMillis();
        }

        public String getKey() {
            return key;
        }

        public String getVlaue() {
            return vlaue;
        }


        @SuppressWarnings("AliControlFlowStatementWithoutBraces")
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            TokenExpiry that = (TokenExpiry) o;

            return key != null ? key.equals(that.key) : that.key == null;
        }

        @Override
        public int hashCode() {
            return key != null ? key.hashCode() : 0;
        }
    }
}
